﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using exMath.Common;

namespace exMath.Calculus
{
    public class Integral
    {
        protected MathFunction _f;
        protected bool _fromderivative;
        protected Derivative _derivative;

        public static Integral operator +(Integral i1, Integral i2)
        {
            if (i1.a == i2.a && i1.b == i2.b)
            {
                return new Integral(delegate(double x)
                {
                    return i1.Function(x) + i2.Function(x);
                }, i1.a, i1.b);
            }
            else
            {
                throw new Exception("A and b ranges are not equal.");
            }
        }

        public static Integral operator -(Integral i1, Integral i2)
        {
            if (i1.a == i2.a && i1.b == i2.b)
            {
                return new Integral(delegate(double x)
                {
                    return i1.Function(x) - i2.Function(x);
                }, i1.a, i1.b);
            } 
            else
            {
                throw new Exception("A and b ranges are not equal.");
            }
        }

        public static Integral operator *(Integral i1, double c)
        {
            return new Integral(delegate(double x)
                {
                    return i1.Function(x) * c;
                }, i1.a, i1.b);
        } 
        
        public MathFunction Function
        {
            get
            {
                return _f;
            }
        }

        public double a
        {
            get; 
            protected set;
        }

        public double b
        {
            get;
            protected set;
        }

        public double IntervalCount
        {
            get;
            set;
        }

        /// <summary>
        /// this executes an integral calculation within the boundaries from a -> x.
        /// </summary>
        public MathFunction g
        {
            get
            {
                return _g;
            }
        }

        private double _g(double x)
        {
            Integral tmpIntegral = new Integral(_f, a, x, IntervalCount);
            return tmpIntegral.GetIntegralResult();
        }

        /// <summary>
        /// Generates a derivative from this integral.
        /// </summary>
        /// <returns></returns>
        public Derivative Getderivative()
        {
            return new Derivative(this);
        }

        public Integral(Derivative d, double a, double b)
        {
            _fromderivative = true;
            _derivative = d;
            this.a = a;
            this.b = b;
        }

        public Integral(MathFunction f, double a, double b)
        {
            _f = f;
            this.a = a;
            this.b = b;
            this.IntervalCount = 100;
        }

        public Integral(MathFunction f, double a, double b, double IntervalCount)
        {
            _f = f;
            this.a = a;
            this.b = b;
            this.IntervalCount = IntervalCount;
        }

        protected virtual double PerformIntegration(double n)
        {
            IntervalCount = n;

            return BasicOperations.Sum(a, b, n, delegate(double x)
            {
                return _f(x) * n;
            });
        }

        public double GetIntegralResult()
        {
            if (_fromderivative)
                return 0;
            else
                return PerformIntegration((b - a) / IntervalCount);
        }
    }
}
